package service

import (
	"errors"
	"fmt"
	"ruoyi-go-echo-ddd/internal/domain/model"
	"ruoyi-go-echo-ddd/internal/infrastructure/persistence/config"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"
	"time"

	"github.com/go-redis/redis/v8"
	"github.com/golang-jwt/jwt/v5"
	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog"
)

type TokenService struct {
	redisClient *redis.Client
}

func NewTokenService(client *redis.Client) *TokenService {
	return &TokenService{
		redisClient: client,
	}
}

func (s *TokenService) CreateToken(e echo.Context, loginUser *model.LoginUser) (string, error) {
	// 创建token
	claims := model.MyClaims{
		Uuid:     loginUser.Uuid,
		Username: loginUser.Username,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    "ry-go-server",
			Subject:   loginUser.Uuid,
			Audience:  jwt.ClaimStrings{"test", "api-service"},
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.JwtConfig.Duration)), // 过期时间
			NotBefore: jwt.NewNumericDate(time.Now()),                                // 可选：生效时间
			IssuedAt:  jwt.NewNumericDate(time.Now()),                                // 签发时间
			ID:        utils.ShortUUID(),
		},
	}

	tokenClaim := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenStr, err := tokenClaim.SignedString([]byte(config.JwtConfig.Secret))
	if err != nil {
		zerolog.DefaultContextLogger.Error().AnErr("创建jwt凭证错误===", err).Msg("")
		return "", errors.New("用户凭证信息返回错误，请稍后重试")
	}

	cacheKey := config.CacheConfig.Login.Prefix + loginUser.Uuid
	zerolog.DefaultContextLogger.Info().Msgf("登陆用户缓存key===%s，数据key===%+v，缓存时长===%v", cacheKey, loginUser, config.CacheConfig.Login.Expiration*3)
	// 缓存登陆用户信息，有效期为30分钟
	result, err := utils.Set(e.Request().Context(), s.redisClient,
		cacheKey,
		loginUser,
		config.CacheConfig.Login.Expiration*3)
	if err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msgf("登陆用户缓存错误，缓存key===%s", cacheKey)
		return "", errors.New("用户凭证信息返回错误，请稍后重试")
	}
	zerolog.DefaultContextLogger.Info().Msgf("用户凭证缓存设置结果===%s，缓存key===%s", result, cacheKey)

	return tokenStr, nil
}

func (s *TokenService) CacheToken(e echo.Context, uuid, token string) error {
	cacheKey := config.CacheConfig.Auth.Prefix + uuid
	// 凭证存入redis
	result, err := utils.Set(e.Request().Context(), s.redisClient, cacheKey, token, config.CacheConfig.Auth.Expiration)
	if err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msgf("用户请求凭证设置缓存错误，缓存key===%s", cacheKey)
		return err
	}
	zerolog.DefaultContextLogger.Info().Msgf("用户请求凭证设置缓存返回结果===%s，缓存key===%s", result, cacheKey)
	return nil
}

func (s *TokenService) GetLoginUser(e echo.Context) (*model.LoginUser, error) {
	var loginUser *model.LoginUser

	token, err := s.GetToken(e, config.JwtConfig.RespHeaderKey, config.JwtConfig.AuthPrefix)
	if err != nil {
		return nil, err
	}

	if token == "" {
		return nil, errors.New("未找到登录凭证")
	}
	myClaims, err := utils.ParseToken(token, config.JwtConfig.Secret)
	if err != nil {
		return nil, err
	}
	// 获取用户缓存信息
	userCacheKey := config.CacheConfig.Login.Prefix + myClaims.Uuid

	loginUser, err = utils.GetTyped(e.Request().Context(), s.redisClient, userCacheKey, loginUser)
	if err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("用户数据反序列化失败")
		return nil, fmt.Errorf("解析用户信息失败: %w", err)
	}

	// 验证用户uuid一致性
	if loginUser.Uuid != myClaims.Uuid {
		zerolog.DefaultContextLogger.Warn().
			Str("claimUuId", myClaims.Uuid).
			Int64("redisUuid", loginUser.UserId).
			Msg("JWT用户uuid与用户缓存uuid不一致")
		return nil, errors.New("用户信息不匹配")
	}

	return loginUser, nil
}

func (s *TokenService) SetLoginUser(e echo.Context, loginUser *model.LoginUser) error {
	// 设置登陆时间与过期时间
	loginUser.LoginTime = time.Now().Unix()
	loginUser.ExpireTime = time.Now().Add(config.CacheConfig.Login.Expiration).Unix()

	loginUserCacheKey := config.CacheConfig.Login.Prefix + loginUser.Uuid
	rs, err := utils.Set(e.Request().Context(), s.redisClient,
		loginUserCacheKey,
		loginUser,
		config.CacheConfig.Login.Expiration)
	if err != nil {
		zerolog.DefaultContextLogger.Error().Msgf("用户信息缓存失败===%+v", err)
		return err
	}

	zerolog.DefaultContextLogger.Info().Msgf("设置用户登陆信息缓存key===%s结果===%s\n用户信息===%s", loginUserCacheKey, rs, utils.ToJsonFormat(loginUser))
	return nil
}

func (s *TokenService) DeleteLoginUser(e echo.Context) error {
	loginUser, err := s.GetLoginUser(e)
	if err != nil {
		zerolog.DefaultContextLogger.Error().AnErr("获取登陆用户信息错误", err).Msg("")
		return err
	}
	// 删除缓存的用户信息
	userCount, err := utils.Del(e.Request().Context(), s.redisClient, config.CacheConfig.Login.Prefix+loginUser.Uuid)
	if err != nil {
		zerolog.DefaultContextLogger.Error().AnErr("用户信息缓存删除错误", err).Msg("")
		return err
	}
	zerolog.DefaultContextLogger.Info().Msgf("用户缓存ID===%d删除结果===%d", loginUser.UserId, userCount)

	// 删除缓存token
	tokenCount, err := utils.Del(e.Request().Context(), s.redisClient,
		config.CacheConfig.Auth.Prefix+loginUser.Uuid)
	if err != nil {
		zerolog.DefaultContextLogger.Error().AnErr("用户凭证缓存删除错误", err).Msg("")
		return err
	}
	zerolog.DefaultContextLogger.Info().Msgf("用户凭证ID===%d删除结果===%d", loginUser.UserId, tokenCount)
	return nil
}

func (s *TokenService) GetToken(e echo.Context, tokenKey, authPrefix string) (string, error) {
	return utils.GetJwtTokenFromEcho(e, tokenKey, authPrefix)
}
